//
//  YLPaymentManager.swift
//  YLPaymentKit
//
//  Created by changhe on 2025/4/12.
//

import Foundation
import StoreKit

/// 支付回调类型
public typealias YLPaymentCallback = (YLPaymentResult) -> Void

/// 支付管理器，用于处理各种支付方式
public class YLPaymentManager {
    
    // MARK: - 属性
    
    /// 处理器映射
    private var processors: [YLPaymentType: YLPaymentProcessor] = [:]
    
    /// 支付配置
    private var config: YLPaymentConfig?
    
    ///收据管理
    private let receiptManager: YLReceiptRefreshRequest = YLReceiptRefreshRequest()
    
    // MARK: - 初始化
    
    /// 初始化方法 - 使用配置
    public init(config: YLPaymentConfig = YLPaymentConfig()) {
        self.config = config
        YLOrderUUIDTransformer.configure(with: config.orderIdConverter)
        
        // 根据配置自动注册处理器
        registerProcessorsBasedOnConfig(config)
    }

    // MARK: - 公共方法
    
    /// 设置支付配置
    public func setup(config: YLPaymentConfig) {
        self.config = config
        
        // 清空现有处理器
        processors.removeAll()
        
        // 根据新配置注册处理器
        registerProcessorsBasedOnConfig(config)
    }
    
    /// 注册支付处理器
    /// - Parameter processor: 支付处理器
    public func registerProcessor(_ processor: YLPaymentProcessor) {
        processors[processor.paymentType] = processor

        if let config = self.config {
            processor.setup(config: config)
        }
        
        debugPrint("已注册支付处理器: \(processor.paymentType)")
    }
    
    /// 检查处理器是否可用
    /// - Parameter type: 支付类型
    /// - Returns: 是否可用
    public func isProcessorAvailable(for type: YLPaymentType) -> Bool {
        guard let processor = processors[type] else {
            return false
        }
        return processor.isAvailable
    }
    
    /// 发起支付
    /// - Parameters:
    ///   - type: 支付类型
    ///   - params: 支付参数
    ///   - completion: 支付结果回调
    public func pay(type: YLPaymentType, params: YLPaymentParams, validator: YLTransactionValidator? = nil, completion: @escaping YLPaymentCallback) {
        guard let processor = processors[type] else {
            completion(.failure(.processorNotFound))
            return
        }
        processor.handlePayment(params: params) { [weak self]result in
            guard let validator, case .success(let transaction) = result, let transactionInfo = transaction.transactionInfo, let self else {
                completion(result)
                return
            }
            self.verifyReceipt(using: validator, transaction: transactionInfo, completion: completion)
        }
    }
    
    /// 发起支付（使用YLPaymentModel）
    /// - Parameters:
    ///   - model: 支付模型
    ///   - completion: 支付结果回调
    public func pay(model: YLPaymentModel, validator: YLTransactionValidator? = nil, completion: @escaping (YLPaymentResult) -> Void) {
        // 获取对应类型的处理器
        guard let processor = processors[model.paymentType] else {
            completion(.failure(.processorNotFound))
            return
        }
        
        // 检查处理器是否可用
        guard processor.isAvailable else {
            completion(.failure(.sdkNotAvailable))
            return
        }
        
        // 调用处理器进行支付
        processor.handlePayment(params: model.params) { [weak self]result in
            guard let validator, case .success(let transaction) = result, let transactionInfo = transaction.transactionInfo, let self  else {
                completion(result)
                return
            }
            
            self.verifyReceipt(using: validator, transaction: transactionInfo, completion: completion)
        }
    }
    
    
    /// 发起内购支付（便捷方法）
    public func payIAP(productId: String, orderId: String, validator: YLTransactionValidator? = nil, completion: @escaping (YLPaymentResult) -> Void) {
        let params = YLIAPParams(productId: productId, orderId: orderId)
        
        let model = YLPaymentModel(paymentType: .iap, params: params)
        
        pay(model: model,  validator: validator, completion: completion)
    }
    
    /// 发起支付宝支付（便捷方法 - 使用已拼接的参数）
    public func payAlipay(orderId: String, paymentString: String, completion: @escaping (YLPaymentResult) -> Void) {
        let params = YLAlipayParams(orderId: orderId, paymentString: paymentString)
        
        let model = YLPaymentModel(paymentType: .alipay, params: params)
        
        pay(model: model, completion: completion)
    }

    /// 发起微信支付（便捷方法）
    public func payWechat(
        orderId: String,
        amount: Double,
        description: String,
        appId: String,
        partnerId: String,
        prepayId: String,
        package: String,
        nonceStr: String,
        timeStamp: String,
        sign: String,
        completion: @escaping (YLPaymentResult) -> Void
    ) {
        let params = YLWechatParams(
            orderId: orderId,
            amount: amount,
            description: description,
            openId: nil,
            appId: appId,
            partnerId: partnerId,
            prepayId: prepayId,
            nonceStr: nonceStr,
            timeStamp: timeStamp,
            package: package,
            sign: sign
        )
        
        let model = YLPaymentModel(paymentType: .wechat, params: params)
        
        pay(model: model, completion: completion)
    }
    
    /// 恢复内购购买（便捷方法）
    public func restoreIAPPurchases(completion: @escaping (YLPaymentResult) -> Void) {
        // 获取IAP处理器
        guard let processor = processors[.iap] as? YLIAPProcessor else {
            completion(.failure(.processorNotFound))
            return
        }
        
        // 调用恢复购买
        processor.restorePurchases(completion: completion)
    }
    
    /// 处理URL回调
    public func handleOpenURL(_ url: URL) -> Bool {
        // 遍历所有处理器，查找能处理该URL的处理器
        for processor in processors.values {
            if processor.canHandleURL(url) {
                return processor.handleURL(url)
            }
        }
        
        return false
    }
    
    /// 获取IAP商品信息
    /// - Parameters:
    ///   - productIds: 商品ID数组
    ///   - completion: 结果回调
    public func fetchProducts(productIds: [String], completion: @escaping (Result<[Any], Error>) -> Void) {
        guard let iapProcessor = processors[.iap] as? YLIAPProcessor else {
            completion(.failure(YLPaymentError.processorNotFound))
            return
        }
        
        iapProcessor.fetchProducts(productIds: productIds, completion: completion)
    }
    
    /// 检查未完成的交易
    public func checkUnfinishedTransactions(completHandler: (([YLTransactionInfo]) -> Void)?) {
        guard let iapProcessor = processors[.iap] as? YLIAPProcessor else {
            completHandler?([])
            return
        }
        
        iapProcessor.checkUnfinishedTransactions(completHandler: completHandler)
    }
    
    /// 完成交易
    /// - Parameter transaction: 交易对象
    public func finishTransaction(_ transaction: Any) {
        guard let iapProcessor = processors[.iap] as? YLIAPProcessor else {
            return
        }
        if let skTransaction = transaction as? SKPaymentTransaction {
            iapProcessor.finishTransaction(skTransaction)
        } else if #available(iOS 15.0, *) {
            iapProcessor.finishTransaction(transaction)
        } else {
            print("[YLPaymentKit] 无法完成交易：不支持的交易类型")
        }
    }

    // MARK: - 私有方法
    
    /// 根据配置注册处理器
    private func registerProcessorsBasedOnConfig(_ config: YLPaymentConfig) {
        registerProcessor(YLIAPProcessor())
    }
    
}

extension YLPaymentManager {
    /// 验证交易收据
    ///
    /// 此方法通过以下步骤验证交易:
    /// 1. 检查IAP处理器是否可用
    /// 2. 从设备获取收据数据(可选择强制刷新)
    /// 3. 使用提供的验证器验证交易信息和收据数据
    /// 4. 验证成功时完成交易并返回成功结果
    /// 5. 验证失败时返回相应错误信息
    ///
    /// 注意：您需要实现并提供一个符合 YLTransactionValidator 协议的验证器来处理实际的收据验证逻辑。
    /// YLPaymentKit 不包含实际的收据验证逻辑，而是将验证工作委托给您提供的验证器。
    ///
    /// - Parameters:
    ///   - validator: 用于验证交易的交易验证器，必须符合 YLTransactionValidator 协议
    ///   - transaction: 需要验证的交易信息
    ///   - forceRefresh: 是否强制刷新收据数据，默认为false
    ///   - completion: 验证完成后的回调，参数为验证结果
    ///      - 成功时返回YLPaymentResult.success，包含交易详细信息
    ///      - 失败时返回YLPaymentResult.failure，包含具体错误原因
    public func verifyReceipt(using validator: YLTransactionValidator, transaction: YLTransactionInfo, forceRefresh: Bool = false, completion: @escaping (YLPaymentResult) -> Void) {
        guard processors[.iap] is YLIAPProcessor else {
            completion(.failure(YLPaymentError.processorNotFound))
            return
        }
        
        receiptManager.getReceipt(forceRefresh: forceRefresh, version: config?.iapVersion ?? .auto) { result in
            switch result {
            case .success(let data):
                let receiptData: Data
                let isJws: Bool
                switch data {
                case .json(let jsonData):
                    receiptData = jsonData
                    isJws = true
                case .legacy(let legacyData):
                    receiptData = legacyData
                    isJws = false
                }
                validator.verifyTransaction(transaction: transaction, receiptData: receiptData, receiptDataIsJws: isJws) { isSuccess, error in
                    if let error {
                        completion(.failure(.verifyError(error)))
                    } else {
                        
                        self.finishTransaction(transaction.rawTransaction)
                        completion(.success(YLPaymentResultData(orderId: transaction.orderId ?? "",
                                                                transactionId: transaction.transactionId,
                                                                productId: transaction.productId,
                                                                transactionDate: transaction.transactionDate,
                                                                originalTransactionId: transaction.originalTransactionId,
                                                                transactionInfo: transaction,
                                                                rawInfo: transaction.rawTransaction)))
                    }
                }
            case .failure:
                completion(.failure(.receiptNotFound))
            }
        }
    }
}
